package se.webbzon.boltzmann.game.sequence;

import se.webbzon.boltzmann.game.event.*;
import se.webbzon.boltzmann.game.event.predefined.*;
import se.webbzon.oschi01.worldobject.WorldObject;

public class GameEventSequenceNode extends SequenceNode implements GameEventListener {
	
	// The game event associated with this sequence node
	private final GameEventEnum gameEvent;
	
	// The next sequence node
	private SequenceNode branch;
		
	// The current game event in action
	private AbstractGameEvent event;	
	
	// The arguments of this game event sequence
	private String[] arguments;
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Creates a new game event sequence node. **/
	public GameEventSequenceNode(	Sequence sequence, 
									GameEventEnum gameEvent,
									String[] arguments) {
		super(sequence);
		this.gameEvent = gameEvent;
		this.arguments = arguments;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Sets the next sequence node related to this game event 
	 * sequence node. If this node is a leaf then the next node 
	 * should be null. **/
	public void setBranch(SequenceNode branch) {
		this.branch = branch;
	}

	@Override public void onBegin(AbstractGameEvent event) {};

	@Override public void onEnd(AbstractGameEvent event) {
		event.removeListener(this);
		this.event = null;
		getSequence().next(0);
	}

	@Override public int branches() {
		return (branch == null) ? 0 : 1;
	}

	@Override public SequenceNode getBranch(int n) {
		return branch;
	}
	
	/*============================================================
	Protected Methods
	============================================================*/

	@Override protected void onBegin(WorldObject binding) { 
		event = toEvent(gameEvent,binding);
		
		if (event != null) {
			event.addListener(this);
			event.begin(getSequence().getWorld());
		} else
			getSequence().next(0);
	}

	@Override protected void onEnd(WorldObject binding) {
		if (event != null)
			event.end();
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Returns a new instant of an abstract game event which is
	 * associated with the provided game event enumeration. **/
	private final AbstractGameEvent toEvent(GameEventEnum gameEvent, 
											WorldObject binding) {
		switch (gameEvent) {
		case doNothing: return new DoNothingEvent();
		case sleep: return new SleepEvent(arguments);
		case setEnable: return new SetEnableEvent(binding,true,false);
		case setDisable: return new SetEnableEvent(binding,false,false);
		case setInstantEnable: return new SetEnableEvent(binding,true,true);
		case setInstantDisable: return new SetEnableEvent(binding,false,true);
		case storeItem: return new StoreItemEvent(arguments,getSequence());
		case removeItem: return new RemoveItemEvent(arguments,getSequence());
		case giveItem: return new GiveItemEvent(arguments,getSequence());
		case placeItem: return new PlaceItemEvent(arguments,getSequence(),binding);
		case pickupItem: return new PickupItemEvent(arguments,getSequence(),binding);
		case itemToName: return new ItemToNameEvent(arguments,getSequence());
		case itemToId: return new ItemToIdEvent(arguments,getSequence());
		case setCamera: return new SetCameraEvent(getSequence(),binding,false);
		case setCameras: return new SetCameraEvent(getSequence(),binding,true);
		case resetCamera: return new ResetCameraEvent(getSequence(),false);
		case resetCameras: return new ResetCameraEvent(getSequence(),true);
		case setGameCameraTarget: return new SetGameCameraTargetEvent(getSequence(),arguments,false,false);
		case resetGameCameraTarget: return new SetGameCameraTargetEvent(getSequence(),arguments,false,true);
		case setGameCameraTargets: return new SetGameCameraTargetEvent(getSequence(),arguments,true,false);
		case resetGameCameraTargets: return new SetGameCameraTargetEvent(getSequence(),arguments,true,true);
		case startCinema: return new CinemaStartEvent(getSequence(),arguments); 
		case endCinema: return new CinemaEndEvent();
		case spawn: return new SpawnEvent(getSequence(),binding,arguments);
		case setTarget: return new SetTargetEvent(getSequence(),binding,arguments);
		case walkTo: return new WalkToEvent(getSequence(), binding, arguments, true, false);
		case setCameraTarget: return new SetCameraTargetEvent(getSequence(), arguments, binding);
		case loopMusic: return new MusicEvent(arguments,true); 
		case playMusic: return new MusicEvent(arguments,false); 
		case stopMusic: return new MusicEvent(null,true); 
		case playSound: return new SoundEvent(arguments);
		case predefined: return new PredefinedEvent(getSequence(), binding, arguments);
		case lookAt: return new LookAtEvent(getSequence(), binding, arguments);
		case jumpTo: return new JumpToEvent(getSequence(), binding, arguments);
		case spinTo: return new SpinToEvent(getSequence(), binding, arguments);
		case teleportTo: return new TeleportToEvent(getSequence(), binding, arguments);
		case walkTowards: return new WalkToEvent(getSequence(), binding, arguments, false, false);
		case disappearTowards: return new WalkToEvent(getSequence(), binding, arguments, false, true);
		case npcFreeze: return new NPCFreezeEvent(binding);
		case npcStand: return new NPCStandEvent(binding);
		case npcWalk: return new NPCWalkEvent(binding);
		case npcGuard: return new NPCGuardEvent(getSequence(), binding, arguments);
		case npcStalk: return new NPCStalkEvent(binding);
		case destroy: return new DestroyEvent(binding);
		}
		return null;
	}

}
